using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;

namespace Universe.JRun
{
    public class JRunner
    {
        private string _EntryClass;
        private string _classPath;
        private JDescription _JRE;


        public JRunner(string entryClass)
        {
            _EntryClass = entryClass;
        }


        public JRunner(string entryClass, string classPath)
        {
            _EntryClass = entryClass;
            _classPath = classPath;
        }


        public string EntryClass
        {
            get { return _EntryClass; }
            set { _EntryClass = value; }
        }


        public string ClassPath
        {
            get { return _classPath; }
            set { _classPath = value; }
        }


        public JDescription JRE
        {
            get { return _JRE; }
            set { _JRE = value; }
        }

        public JResponse Run(params string[] args)
        {
            string cp = ClassPath;

            StringBuilder ab = new StringBuilder();
            foreach (string s in args)
                ab.Append(" \"").Append(s).Append("\"");

            JDescription jre = GetJRE();
            ProcessStartInfo si = new ProcessStartInfo(
                Path.Combine(jre.Path, "bin\\java.exe"),
                (string.IsNullOrEmpty(cp) ? "" : ("-cp \"" + cp + "\" "))
                + EntryClass + " "
                + ab);

            // Trace.WriteLine("");
            // Trace.WriteLine("\"" + si.FileName + "\"" + " " + si.Arguments);

            si.UseShellExecute = false;
            si.CreateNoWindow = true;
            si.ErrorDialog = true;
            si.RedirectStandardError = true;
            si.RedirectStandardOutput = true;
            si.StandardErrorEncoding = new UTF8Encoding(false);
            si.StandardOutputEncoding = new UTF8Encoding(false);
            using (Process p = Process.Start(si))
            {
                string errors = null, output = null;
                int exitCode;
                Thread
                    t1 = new Thread(
                        delegate()
                            {
                                errors = p.StandardError.ReadToEnd();
                            }),
                    t2 = new Thread(
                        delegate()
                            {
                                output = p.StandardOutput.ReadToEnd();
                            }
                        ),
                    t3 = new Thread(
                        delegate()
                            {
                                p.WaitForExit();
                            });

                t1.IsBackground = t2.IsBackground = t3.IsBackground = true;
                t1.Start();
                t2.Start();
                t3.Start();
                t1.Join();
                t2.Join();
                t3.Join();


                JResponse response = new JResponse(
                    p.ExitCode,
                    output,
                    errors);

                return response;
            }
        }

        private JDescription GetJRE()
        {
            JDescription j = JRE;
            if (j == null || !j.Exists)
                j = JDescriptions.JRE.Current;

            return j;
        }
    }
}
